package com.ticket.sass.common.douyin.openapi

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import com.ticket.sass.common.douyin.openapi.enums.CertificateStatus
import com.ticket.sass.common.douyin.openapi.enums.GoodsStatus
import com.ticket.sass.common.douyin.openapi.enums.UniversalEnumDeserializer
import com.ticket.sass.common.douyin.openapi.resposne.ApiResponse
import com.ticket.sass.common.douyin.openapi.resposne.ApiResponseBaseData
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Request
import org.slf4j.Logger
import okio.Buffer
import java.io.IOException
import java.lang.reflect.Type
import java.nio.charset.Charset
import java.time.Duration
import java.time.LocalDateTime

open class BaseClient(
    private val host: String = "https://open.douyin.com",
    private var client: OkHttpClient = OkHttpClient(),
    private var accessToken: String = "",
    private val gson: Gson = GsonBuilder()
        .registerTypeAdapter(GoodsStatus::class.java, UniversalEnumDeserializer(GoodsStatus::class.java))
        .registerTypeAdapter(CertificateStatus::class.java, UniversalEnumDeserializer(CertificateStatus::class.java))
        .create()
) {
    fun setLogger(logger: Logger) {
        client = client.newBuilder().addInterceptor(Interceptor { chain ->
            val request = chain.request()

            val requestBody = request.body?.let {
                val requestBodyBuffer = Buffer()
                it.writeTo(requestBodyBuffer)
                requestBodyBuffer.readString(Charset.forName("UTF-8"))
            }

            val beginTime = LocalDateTime.now()
            val response = chain.proceed(request)

            val responseBody = response.body?.let {
                it.source().request(Long.MAX_VALUE)
                it.source().buffer.clone().readString(Charset.forName("UTF-8"))
            }

            val endTime = LocalDateTime.now()
            val between = Duration.between(beginTime, endTime)
            val millis = between.toMillis()

            logger.info("请求时间：${millis}毫秒, 请求地址：${request.url}，请求参数：${requestBody}，响应状态码：${response.code}，响应数据：${responseBody}")

            response
        }).build()
    }

    protected fun buildUrl(path: String): String {
        return "$host/$path"
    }

    fun getHttpClient(): OkHttpClient {
        return client
    }

    fun getAccessToken(): String {
        return accessToken
    }

    fun setAccessToken(token: String) {
        accessToken = token
    }


    inline fun <reified T> getTypeToken(): Type {
        return object : TypeToken<T>() {}.type
    }

    /**
     * 使用内联
     */
    protected fun <T : ApiResponseBaseData> doRequest(builder: Request.Builder, classType: Class<T>): T {
        val req = builder
            .addHeader("Content-Type", "application/json")
            .addHeader("access-token", accessToken)
            .build()

        client.newCall(req).execute().use { response ->
            if (!response.isSuccessful) throw IOException("Unexpected code $response")
            try {
                val typeToken =
                    TypeToken.getParameterized(ApiResponse::class.java, classType).type
                val content = response.body!!.string()
                println(content)
                val apiResponse: ApiResponse<T> = gson.fromJson(content, typeToken)


                // 深拷贝
//                val copy: ApiResponse<T> = Gson().fromJson(Gson().toJson(apiResponse), typeToken)
//                apiResponse.data.setMetadata(copy)

                return apiResponse.data
            } catch (e: Exception) {
                throw IOException("Gson from Json exception", e)
            }
        }
    }

}
